package javabasics.task4;
import java.util.Scanner;
import java.lang.Object;
import java.util.Date;
import java.lang.IllegalArgumentException;
import java.util.InputMismatchException;

public class WeekDay{

  private static final String REGEXP_CORRECT_DATE = "(0?[1-9]|[12][0-9]|3[01])[\\s](0?[1-9]|1[012])[\\s]((17|18|19|20|21|22|23|24|25|26|)\\d\\d)$";

  public static void main(String[] args){
    String[] dateArray = readInputIntoArrayOfString();
    int day = Integer.parseInt(dateArray[0]);
    int month = Integer.parseInt(dateArray[1]);
    int year = Integer.parseInt(dateArray[2]);

    System.out.print("Your Date corresponds to: " + getWeekDayName(day,month,year));
  }

  private static String[] readInputIntoArrayOfString() {
	System.out.println("Input your Date in the format DD MM YYYY. Be in 1700 - 2699 range:");
    Scanner input = new Scanner(System.in);
    String date = input.nextLine();
    while(!date.matches(REGEXP_CORRECT_DATE)){
    	System.out.println("Invalid Date. Input your Date in the format DD MM YYYY. Be in 1700 - 2699 range:");
    	input = new Scanner(System.in);
    	date = input.nextLine();
    }
    String[] dateArray = date.split(" ");
    input.close();
	return dateArray;
  } 

  enum CenturyCode{
   	EIGHTEENTH(4), NINETEENTH(2), TWENTIETH(0), TWENTYFIRST(6), TWENTYSECOND(4), 
	TWENTYTHIRD(2), TWENTYFORTH(0),TWENTYFIFTH(6), TWENTYSIXTH(4), TWENTYSEVENTH(2);
	CenturyCode(int number){
	  this.number = number;
        }
        private int number;
        public int getNumber(){
	  return number;
  }

   private static CenturyCode getCentuary(int yearInput){
      if (yearInput>=1700 && yearInput<=1799) return CenturyCode.EIGHTEENTH;
      if (yearInput>=1800 && yearInput<=1899) return CenturyCode.NINETEENTH;
      if (yearInput>=1900 && yearInput<=1999) return CenturyCode.TWENTIETH;
      if (yearInput>=2000 && yearInput<=2099) return CenturyCode.TWENTYFIRST;
      if (yearInput>=2100 && yearInput<=2199) return CenturyCode.TWENTYSECOND;
      if (yearInput>=2200 && yearInput<=2299) return CenturyCode.TWENTYTHIRD;
      if (yearInput>=2300 && yearInput<=2399) return CenturyCode.TWENTYFORTH;
      if (yearInput>=2400 && yearInput<=2499) return CenturyCode.TWENTYFIFTH;
      if (yearInput>=2500 && yearInput<=2599) return CenturyCode.TWENTYSIXTH;
      if (yearInput>=2600 && yearInput<=2699) return CenturyCode.TWENTYSEVENTH;
      return null;
   }
  }

  interface Month{
    int getNumber();
  }

  enum MonthCommon implements Month{
	JANUARY(0), FEBRUARY(3), MARCH(3), APRIL(6), MAY(1), JUNE(4), JULY(6), AUGUST(2), 
 	SEPTEMBER(5), OCTOBER(0), NOVEMBER(3), DECEMBER(5);
        MonthCommon(int number){
	  this.number = number;
        }
        private int number;
        public int getNumber(){
	  return number;
	}
  }

  enum MonthLeap implements Month{
	JANUARY(6), FEBRUARY(2), MARCH(3), APRIL(6), MAY(1), JUNE(4), JULY(6), AUGUST(2), 
	SEPTEMBER(5), OCTOBER(0), NOVEMBER(3), DECEMBER(5);
        MonthLeap(int number){
	  this.number = number;
        }
        private int number;
        public int getNumber(){
	  return number;
	}
  }

  private static Month getMonthName(int isLeap, int monthInput){
      if (monthInput==1 && isLeap==0) return MonthLeap.JANUARY;
      if (monthInput==1 && isLeap!=0) return MonthCommon.JANUARY;
      if (monthInput==2 && isLeap==0) return MonthLeap.FEBRUARY;
      if (monthInput==2 && isLeap!=0) return MonthCommon.FEBRUARY;
      if (monthInput==3 && isLeap==0) return MonthLeap.MARCH;
      if (monthInput==3 && isLeap!=0) return MonthCommon.MARCH;
      if (monthInput==4 && isLeap==0) return MonthLeap.APRIL;
      if (monthInput==4 && isLeap!=0) return MonthCommon.APRIL;
      if (monthInput==5 && isLeap==0) return MonthLeap.MAY;
      if (monthInput==5 && isLeap!=0) return MonthCommon.MAY;
      if (monthInput==6 && isLeap==0) return MonthLeap.JUNE;
      if (monthInput==6 && isLeap!=0) return MonthCommon.JUNE;
      if (monthInput==7 && isLeap==0) return MonthLeap.JULY;
      if (monthInput==7 && isLeap!=0) return MonthCommon.JULY;
      if (monthInput==8 && isLeap==0) return MonthLeap.AUGUST;
      if (monthInput==8 && isLeap!=0) return MonthCommon.AUGUST;
      if (monthInput==9 && isLeap==0) return MonthLeap.SEPTEMBER;
      if (monthInput==9 && isLeap!=0) return MonthCommon.SEPTEMBER;      
      if (monthInput==10 && isLeap==0) return MonthLeap.OCTOBER;
      if (monthInput==10 && isLeap!=0) return MonthCommon.OCTOBER;
      if (monthInput==11 && isLeap==0) return MonthLeap.NOVEMBER;      
      if (monthInput==11 && isLeap!=0) return MonthCommon.NOVEMBER;      
      if (monthInput==12 && isLeap==0) return MonthLeap.DECEMBER;
      if (monthInput==12 && isLeap!=0) return MonthCommon.DECEMBER;
      return null;
  }

  enum WeekDayNameAndNumber{
    SUNDAY(0), MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6);
    WeekDayNameAndNumber(int number){
	  this.number = number;
        }
        private int number;
        public int getNumber(){
	  return number;
	}
  }

  private static WeekDayNameAndNumber getWeekDayName(int tempDay, int tempMonth, int tempYear){

// 1. Get the number for the corresponding century from the centuries table
    int yearCode = CenturyCode.getCentuary(tempYear).getNumber(); 

// 2. Get the last two digits from the year
    int lastTwoDigitsInYear = tempYear % 100;

// 3. Divide the number from step 2 by 4 and get it without the remainder
    int yearIsLeap = lastTwoDigitsInYear / 4;

// 4. Get the month number from the month table
    int monthCode = getMonthName(yearIsLeap,tempMonth).getNumber();
     
// 5. Sum the numbers from steps 1 to 4. Divide it by 7 and take the remainder
    int weekDayNumber = (yearCode + lastTwoDigitsInYear + yearIsLeap + monthCode + tempDay)%7; 

// 6. Find the result of step 6 in the days table
    return WeekDayNameAndNumber.values()[weekDayNumber];
  }
}